package com.fulihui.systemcore.biz.jobs;


import com.fulihui.systemcore.biz.shard.WechatTokenManager;
import com.fulihui.systemcore.dal.dataobj.WechatToken;
import com.fulihui.systemcore.dal.mapper.WechatTokenMapper;
import com.fulihui.systemcore.enums.EnvTypeEnum;
import com.fulihui.systemcore.enums.WechatTokenTypeEnum;
import com.fulihui.systemcore.util.LoggerNameConstants;
import com.fulihui.weixinclient.WeixinClient;
import com.fulihui.weixinclient.request.GetCallbackIPRequest;
import com.fulihui.weixinclient.result.GetCallbackIPResult;
import com.google.common.base.Preconditions;
import org.near.toolkit.common.DateUtils;
import org.near.toolkit.common.EnumUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * 微信token刷新工具，每10分钟执行一次，判断是否快要过时，或者token已经无效，
 * 如果过时或者无效，则更新数据库
 *
 * @author Created by Willard.Hu on 2016/7/20 0020.
 */
@Component
public class WechatTokenRefreshJob {
    private final transient Logger JOB_MONITOR = LoggerFactory
            .getLogger(LoggerNameConstants.JOB_MONITOR);
    private final transient Logger LOG = LoggerFactory.getLogger(getClass());

    /* 超时提前时间刷新 */
    private static final int LEADTIME_S = 5 * 60;

    @Autowired
    private WechatTokenMapper wechatTokenMapper;
    @Autowired
    private WeixinClient weixinClient;
    @Autowired
    private WechatTokenManager wechatTokenManager;
    @Value("${product.env}")
    private String productEnv;


    public void execute() {
        JOB_MONITOR.info("微信token刷新工具开始:{},", DateUtils.formatNewFormat(new Date()));
        if (EnvTypeEnum.DEV.getCode().equals(productEnv)) {
            // 开发环境不执行Token刷新任务
            return;
        }
        List<WechatToken> tokenList = wechatTokenMapper.queryAll();
        if (CollectionUtils.isEmpty(tokenList)) {
            JOB_MONITOR.info("Wechat token is empty!");
            return;
        }
        for (WechatToken token : tokenList) {
            try {
                executeTask(token);
            } catch (Exception e) {
                JOB_MONITOR.error("Refresh token {} execute failed, error message:", token.getId(),
                        e.getMessage());
                LOG.error(e.getMessage(), e);
            }
        }
    }

    private void executeTask(WechatToken token) {
        // 防止异常调用
        if (token == null) {
            throw new IllegalArgumentException("token is null");
        }
        WechatTokenTypeEnum tokenType = EnumUtil.queryByCode(token.getTokenType(),
                WechatTokenTypeEnum.class);

        // 判断授权码是否失效，失效时间提前5分钟判断
        int expiresIn = token.getExpiresIn() - LEADTIME_S;
        Date expiryDate = DateUtils.addSeconds(token.getGmtModified(), expiresIn);
        Date now = new Date();
        boolean needRef = now.after(expiryDate);
        JOB_MONITOR.info("token:{}, now:{}, expiryDate:{}, needRef:{}",
                new Object[]{token.getId(), DateUtils.formatNewFormat(now),
                        DateUtils.formatNewFormat(expiryDate), needRef});

        // 未到失效时间，判断当前授权码是否有效
        if (!needRef) {
            if (tokenType == WechatTokenTypeEnum.ACCESS_TOKEN) {
                GetCallbackIPRequest getCallbackIPRequest = new GetCallbackIPRequest();
                getCallbackIPRequest.setAccess_token(token.getToken());
                GetCallbackIPResult getCallbackIPResult = weixinClient
                        .invokeService(getCallbackIPRequest);
                if (!getCallbackIPResult.isSuccess()) {
                    needRef = true;
                    JOB_MONITOR.info("needRef:true, code:{}, msg:{}",
                            getCallbackIPResult.getErrcode(), getCallbackIPResult.getErrmsg());
                }
            }
        }

        if (needRef) {
            WechatToken newToken = wechatTokenManager.queryRemote(token.getAppid(),
                    token.getSecret(), tokenType);
            boolean b = wechatTokenMapper.update(newToken);
            Preconditions.checkArgument(b, "Update token failed");
            JOB_MONITOR.info("token:{} refresh success!", token.getId());
        } else {
            JOB_MONITOR.info("token:{} don't need to refresh!", token.getId());
        }
    }

}
